package com.jichangxiu.server.platform.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jichangxiu.common.constant.Constant;
import com.jichangxiu.common.entity.bo.PageData;
import com.jichangxiu.common.entity.bo.Record;
import com.jichangxiu.common.exception.ServiceException;
import com.jichangxiu.common.utils.TokenUtils;
import com.jichangxiu.framework.mybatis.BaseServiceImpl;
import com.jichangxiu.server.platform.entity.dto.PlatformRoleQueryDto;
import com.jichangxiu.server.platform.entity.map.PlatformMenuBasic;
import com.jichangxiu.server.platform.entity.map.PlatformMenuPowerBasic;
import com.jichangxiu.server.platform.entity.po.*;
import com.jichangxiu.server.platform.entity.vo.PlatformMenuAddVo;
import com.jichangxiu.server.platform.entity.vo.PlatformMenuEditVo;
import com.jichangxiu.server.platform.entity.vo.PlatformMenuQueryVo;
import com.jichangxiu.server.platform.mapper.PlatformMenuMapper;
import com.jichangxiu.server.platform.service.*;
import com.jichangxiu.server.platform.utils.MenuUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.validation.constraints.NotBlank;
import java.util.ArrayList;
import java.util.List;

/**
 * PlatformMenuServiceImpl:
 *
 * @author Jcx
 * @create 2023-03-08 21:18
 */
@Service
public class PlatformMenuServiceImpl extends BaseServiceImpl<PlatformMenuMapper, PlatformMenu> implements PlatformMenuService {

    @Resource
    private TokenUtils tokenUtils;

    @Resource
    private PlatformMenuMapper platformMenuMapper;

    @Resource
    private PlatformTenantService platformTenantService;

    @Resource
    private PlatformUserService platformUserService;

    @Resource
    private PlatformRoleService platformRoleService;

    @Resource
    private PlatformRoleMenuService platformRoleMenuService;

    @Resource
    private PlatformMenuPowerService platformMenuPowerService;

    /**
     * 新增菜单
     *
     * @param platformMenuAddVo 菜单视图对象
     * @return 菜单数据库对象
     */
    @Override
    public String add(PlatformMenuAddVo platformMenuAddVo) {
        PlatformMenu platformMenu = PlatformMenuBasic.INSTANCE.toPlatformMenu(platformMenuAddVo);
        if (StrUtil.isNotBlank(platformMenu.getMenuId()) || StrUtil.isBlank(platformMenu.getName())) {
            throw ServiceException.build("菜单参数有误");
        }
        List<PlatformMenu> platformMenuList = list(new LambdaQueryWrapper<PlatformMenu>().in(PlatformMenu::getName, platformMenuAddVo.getName()));
        if (ObjectUtil.isNotEmpty(platformMenuList)) {
            throw ServiceException.build(platformMenuAddVo.getName() + " 该名称的菜单已存在，不能重复创建");
        }
        platformMenu.setMetaHidden(false);
        platformMenu.setMetaHiddenBreadcrumb(false);
        if (!save(platformMenu)) {
            throw ServiceException.build("新增菜单失败");
        }
        return platformMenu.getMenuId();
    }

    /**
     * 删除菜单
     *
     * @param menuIds 菜单ID
     * @return 菜单数据库对象
     */
    @Override
    public Boolean del(List<String> menuIds) {
        if (ObjectUtil.isEmpty(menuIds)) {
            throw ServiceException.build("菜单ID不存在");
        }
        // 先把对应菜单查询出来
        List<PlatformMenu> platformMenuList = list(new LambdaQueryWrapper<PlatformMenu>().in(PlatformMenu::getMenuId, menuIds));
        if (ObjectUtil.isNull(platformMenuList)) {
            throw ServiceException.build("查询不到有效的菜单");
        }

        platformMenuList.forEach(platformMenu -> {
            if ("home".equals(platformMenu.getName())) {
                throw ServiceException.build("首页不能删除");
            }

            if ("dashboard".equals(platformMenu.getName())) {
                throw ServiceException.build("控制台不能删除");
            }
        });

        // 再把这些菜单的子菜单查询出来
        List<PlatformMenu> platformMenus = list(new LambdaQueryWrapper<PlatformMenu>().in(PlatformMenu::getParentId, menuIds));
        if (ObjectUtil.isNotEmpty(platformMenus)) {
            // 把子菜单和 要删除的菜单 结合到一起
            platformMenuList.forEach(platformMenu -> {
                List<PlatformMenu> subMenuList = new ArrayList<>();
                platformMenus.forEach(subMenu -> {
                    if (platformMenu.getMenuId().equals(subMenu.getParentId())) {
                        subMenuList.add(subMenu);
                    }
                });
                platformMenu.setSubPlatformMenus(subMenuList);
            });
            // 如果要删除的菜单下存在子菜单就不允许他删除
            platformMenuList.forEach(platformMenu -> {
                List<PlatformMenu> subPlatformMenuList = platformMenu.getSubPlatformMenus();
                if (subPlatformMenuList.size() != 0) {
                    throw ServiceException.build(platformMenu.getName() + "该菜单下还有子菜单，不能删除");
                }
            });
        }
        // 删除的同时需要注意删除 菜单 及 权限 和角色关联关系也要一起删除
        boolean b1 = true;
        boolean b2 = true;
        boolean b3 = true;
        if (ObjectUtil.isNotEmpty(platformMenuList)) {
            List<String> powerIds = new ArrayList<>();
            List<PlatformMenuPower> platformMenuPowerList = platformMenuPowerService.list(new LambdaQueryWrapper<PlatformMenuPower>().in(PlatformMenuPower::getMenuId, menuIds));
            if (ObjectUtil.isNotEmpty(platformMenuPowerList)) {
                platformMenuPowerList.forEach(platformMenuPower -> powerIds.add(platformMenuPower.getPowerId()));
            }
            List<String> roleMenuIds = new ArrayList<>();
            List<PlatformRoleMenu> platformRoleMenuList = platformRoleMenuService.list(new LambdaQueryWrapper<PlatformRoleMenu>().in(PlatformRoleMenu::getMenuId, menuIds));
            if (ObjectUtil.isNotEmpty(platformRoleMenuList)) {
                platformRoleMenuList.forEach(platformRoleMenu -> roleMenuIds.add(platformRoleMenu.getId()));
            }
            b1 = removeBatchByIds(menuIds);
            if (ObjectUtil.isNotEmpty(powerIds)) {
                b2 = platformMenuPowerService.removeBatchByIds(powerIds);
            }
            if (ObjectUtil.isNotEmpty(roleMenuIds)) {
                b3 = platformRoleMenuService.removeBatchByIds(roleMenuIds);
            }
        }
        return b1 && b2 && b3;
    }

    /**
     * 修改菜单
     *
     * @param platformMenuEditVo 菜单
     * @return 修改后的数据
     */
    @Override
    public Boolean edit(PlatformMenuEditVo platformMenuEditVo) {
        PlatformMenu platformMenu = PlatformMenuBasic.INSTANCE.toPlatformMenu(platformMenuEditVo);
        // 转换之后如果为空，抛出异常
        if (ObjectUtil.isEmpty(platformMenuEditVo)) {
            throw ServiceException.build("要修改的对象不存在");
        }
        // 根据 id 查找数据库对象
        PlatformMenu dbPlatformMenu = getOne(new LambdaQueryWrapper<PlatformMenu>().eq(PlatformMenu::getMenuId, platformMenu.getMenuId()));
        if (ObjectUtil.isEmpty(dbPlatformMenu)) {
            // 不存在 抛出异常
            throw ServiceException.build("要修改的对象不存在");
        }
        if (!platformMenu.getParentId().equals(dbPlatformMenu.getParentId())) {
            // 修改的范围不包括所属父类
            throw ServiceException.build("菜单所属的父对象不能改变");
        }
        // 如果菜单名字 发生变更 需要保持 名字数据库唯一
        if (!platformMenu.getName().equals(dbPlatformMenu.getName())) {
            if ("home".equals(dbPlatformMenu.getName())) {
                throw ServiceException.build("首页别名不能修改");
            }
            if ("dashboard".equals(dbPlatformMenu.getName())) {
                throw ServiceException.build("控制台别名不能修改");
            }
            // 根据名字去数据库查询
            PlatformMenu dbPlatformMenuChangeName = getOne(new LambdaQueryWrapper<PlatformMenu>().eq(PlatformMenu::getName, platformMenu.getName()));
            if (ObjectUtil.isNotEmpty(dbPlatformMenuChangeName)) {
                // 如果不唯一就抛出异常
                throw ServiceException.build("要修改的菜单：" + platformMenu.getName() + " 别名已存在");
            }
        }

        // 如果名字是 未命名 开头，并且状态修改为 false 不能完成修改
        if (platformMenu.getName().startsWith("未命名") && !platformMenu.getStatus()) {
            throw ServiceException.build("新增菜单不能修改状态为停用");
        }

        // 其他的属性 直接覆盖 DB 对象
        BeanUtil.copyProperties(platformMenu, dbPlatformMenu, true);

        // 查找数据库已有的权限集合
        List<PlatformMenuPower> dbPlatformMenuPowerList = platformMenuPowerService.list(new LambdaQueryWrapper<PlatformMenuPower>().in(PlatformMenuPower::getMenuId, platformMenu.getMenuId()));
        // 转换 权限 集合
        List<PlatformMenuPower> platformMenuPowerList = PlatformMenuPowerBasic.INSTANCE.toPlatformMenuPowerList(platformMenuEditVo.getPlatformMenuPowerEditVoList());

        // 这里要分情况讨论
        List<PlatformMenuPower> addPlatformMenuPower = new ArrayList<>();
        List<String> deletePlatformMenuPower = new ArrayList<>();
        List<PlatformMenuPower> updatePlatformMenuPower = new ArrayList<>();

        // 如果两个对象都是空的
        if (ObjectUtil.isEmpty(platformMenuPowerList) && ObjectUtil.isEmpty(dbPlatformMenuPowerList)) {
            // 这种情况啥也不做
        }
        // 如果两个对象都不是空的
        else if (ObjectUtil.isNotEmpty(platformMenuPowerList) && ObjectUtil.isNotEmpty(dbPlatformMenuPowerList)) {
            // 这种情况最为复杂

            // 先循环遍历视图对象处理新增和修改
            platformMenuPowerList.forEach(platformMenuPower -> {
                // 如果 ID 为空的说明 该对象是 新增对象
                if (StrUtil.isBlank(platformMenuPower.getPowerId())) {
                    platformMenuPower.setMenuId(dbPlatformMenu.getMenuId());
                    addPlatformMenuPower.add(platformMenuPower);
                } else {
                    // 反之则为修改对象 循环数据对象列表
                    for (PlatformMenuPower dbPlatformMenuPower : dbPlatformMenuPowerList) {
                        // 取出 ID 相等的数据库对象
                        if (platformMenuPower.getPowerId().equals(dbPlatformMenuPower.getPowerId())) {
                            // 将页面修改的内容赋值到数据库对象上
                            BeanUtil.copyProperties(platformMenuPower, dbPlatformMenuPower, true);
                            // 加入修改列表
                            updatePlatformMenuPower.add(dbPlatformMenuPower);
                        }
                    }
                }
            });

            // 循环数据库对象处理删除
            dbPlatformMenuPowerList.forEach(dbPlatformMenuPower -> {
                // 默认在视图中不存在
                boolean flag = false;
                // 循环视图对象
                for (PlatformMenuPower platformMenuPower : platformMenuPowerList) {
                    // 如果数据库对象在视图对象列表中存在，说明 没有被删除
                    if (dbPlatformMenuPower.getPowerId().equals(platformMenuPower.getPowerId())) {
                        flag = true;
                        break;
                    }
                }
                // 如果当前数据库对象等于 false 那么代表这个对象在页面上被删除了
                if (!flag) {
                    // 把他加入待删除列表
                    deletePlatformMenuPower.add(dbPlatformMenuPower.getPowerId());
                }
            });
        }
        // 如果一个对象空的，另一个不是空的
        else if (ObjectUtil.isEmpty(platformMenuPowerList) && ObjectUtil.isNotEmpty(dbPlatformMenuPowerList)) {
            // 页面传过来的对象是空的，说明需要把数据库里的数据清空，现在把数据库对象全部加入删除的列表
            dbPlatformMenuPowerList.forEach(platformMenuPower -> deletePlatformMenuPower.add(platformMenuPower.getPowerId()));
        }
        // 如果一个对象空的，另一个不是空的
        else if (ObjectUtil.isNotEmpty(platformMenuPowerList) && ObjectUtil.isEmpty(dbPlatformMenuPowerList)) {
            // 页面传过来的对象是不是空的，而数据库里面的对象是空的，则说明 页面上的所有数据都是新增的，需要把数据全部加入待新增的列表
            platformMenuPowerList.forEach(platformMenuPower -> {
                platformMenuPower.setMenuId(dbPlatformMenu.getMenuId());
                // 如果任意一个对象的ID不为空则说明这个对象是个数据库对象，抛出异常
                if (StrUtil.isNotBlank(platformMenuPower.getPowerId())) {
                    throw ServiceException.build(platformMenuPower.getPowerName() + " 该权限对象数据不正确");
                }
            });
            // 经过校验后没有问题则全部加入待新增列表
            addPlatformMenuPower.addAll(platformMenuPowerList);
        }

        // 数据库操作
        boolean b1 = updateById(dbPlatformMenu);

        // 权限增加列表的操作是否成功 默认成功
        boolean b2 = true;
        // 处理增加列表
        if (ObjectUtil.isNotEmpty(addPlatformMenuPower)) {
            b2 = platformMenuPowerService.saveBatch(addPlatformMenuPower);
        }

        // 权限删除列表的操作是否成功 默认成功
        boolean b3 = true;
        // 处理删除列表
        if (ObjectUtil.isNotEmpty(deletePlatformMenuPower)) {
            b3 = platformMenuPowerService.removeBatchByIds(deletePlatformMenuPower);
        }

        // 权限修改列表的操作是否成功 默认成功
        boolean b4 = true;
        // 处理修改列表
        if (ObjectUtil.isNotEmpty(updatePlatformMenuPower)) {
            b4 = platformMenuPowerService.updateBatchById(updatePlatformMenuPower);
        }
        return b1 && b2 && b3 && b4;
    }

    /**
     * 根据菜单ID查找菜单详情
     *
     * @param menuId 菜单ID
     * @return 菜单对象
     */
    @Override
    public Record info(@NotBlank(message = "菜单ID不能为空") String menuId) {
        PlatformMenu platformMenu = getOne(new LambdaQueryWrapper<PlatformMenu>().eq(PlatformMenu::getMenuId, menuId));
        if (ObjectUtil.isEmpty(platformMenu)) {
            throw ServiceException.build("菜单ID" + menuId + "不存在");
        }
        if (ObjectUtil.isNotEmpty(platformMenu)) {
            List<PlatformMenuPower> platformMenuPowerList = platformMenuPowerService.list(new LambdaQueryWrapper<PlatformMenuPower>().in(PlatformMenuPower::getMenuId, menuId));
            if (ObjectUtil.isNotEmpty(platformMenuPowerList)) {
                MenuUtils.addPowerToMenu(ListUtil.toList(platformMenu), platformMenuPowerList);
            }
            return MenuUtils.convertMenu(platformMenu);
        }
        return Record.getRecord();
    }

    /**
     * 获取所有不需要租户购买的菜单列表
     *
     * @return 菜单列表
     */
    @Override
    public List<PlatformMenu> getNotBuyMenuList() {
        return platformMenuMapper.getNotBuyMenuList();
    }

    /**
     * 根据 租户 用户 获取该用户所拥有的菜单
     *
     * @param userId 用户 ID
     * @return 菜单列表
     */
    @Override
    public List<Record> getMenuListByUser(@NotBlank(message = "用户ID不能为空") String userId) {
        // 查询用户
        PlatformUser platformUser = platformUserService.getOne(new LambdaQueryWrapper<PlatformUser>().eq(PlatformUser::getStatus, true).eq(PlatformUser::getUserId, userId));
        if (ObjectUtil.isEmpty(platformUser)) {
            throw ServiceException.build("用户不存在");
        }
        // 查询关联租户
        PlatformTenant platformTenant = platformTenantService.getOne(new LambdaQueryWrapper<PlatformTenant>().eq(PlatformTenant::getStatus, true).eq(PlatformTenant::getTenantId, platformUser.getTenantId()));
        if (ObjectUtil.isEmpty(platformTenant)) {
            throw ServiceException.build("用户没有关联租户");
        }
        // 查询用户拥有的角色
        List<PlatformRoleQueryDto> platformRoleQueryDtoList = platformRoleService.getRoleListByUser(platformTenant.getTenantId(), platformUser.getUserId());

        if (platformTenant.getIsPlatform()) {
            // 平台级别

            // 是否拥有超级管理员角色
            boolean isPlatformSuperRole = false;
            if (ObjectUtil.isNotEmpty(platformRoleQueryDtoList)) {
                for (PlatformRoleQueryDto platformRoleQueryDto : platformRoleQueryDtoList) {
                    if (Constant.PLATFORM_SUPER_ROLE.equals(platformRoleQueryDto.getRoleCode())) {
                        isPlatformSuperRole = true;
                        break;
                    }
                }
            }

            // 平台超级管理员
            if (Constant.PLATFORM_SUPER_USER.equals(platformUser.getUserCode()) || isPlatformSuperRole) {
                List<PlatformMenu> platformMenuList = list(new LambdaQueryWrapper<PlatformMenu>().eq(PlatformMenu::getStatus, true));
                if (ObjectUtil.isNotEmpty(platformMenuList)) {
                    List<PlatformMenuPower> platformMenuPowerList = platformMenuPowerService.list(new LambdaQueryWrapper<PlatformMenuPower>().in(PlatformMenuPower::getMenuId, MenuUtils.getMenuIds(platformMenuList)));
                    MenuUtils.addPowerToMenu(platformMenuList, platformMenuPowerList);
                }
                return MenuUtils.convertMenu(platformMenuList);
            } else {
                // 平台普通用户
                List<PlatformMenu> platformMenuList = platformMenuMapper.getMenuListByUser(platformTenant.getTenantId(), platformUser.getUserId());
                if (ObjectUtil.isNotEmpty(platformMenuList)) {
                    List<PlatformMenuPower> platformMenuPowerList = platformMenuPowerService.list(new LambdaQueryWrapper<PlatformMenuPower>().in(PlatformMenuPower::getMenuId, MenuUtils.getMenuIds(platformMenuList)));
                    MenuUtils.addPowerToMenu(platformMenuList, platformMenuPowerList);
                }
                return MenuUtils.convertMenu(platformMenuList);
            }

        } else {
            // 租户级别

            // 是否拥有系统管理员角色
            boolean isSystemSuperRole = false;
            if (ObjectUtil.isNotEmpty(platformRoleQueryDtoList)) {
                for (PlatformRoleQueryDto platformRoleQueryDto : platformRoleQueryDtoList) {
                    if (Constant.SYSTEM_SUPER_ROLE.equals(platformRoleQueryDto.getRoleCode())) {
                        isSystemSuperRole = true;
                        break;
                    }
                }
            }

            // 租户超级管理员
            if (Constant.SYSTEM_SUPER_USER.equals(platformUser.getUserCode()) || isSystemSuperRole) {
                List<PlatformMenu> platformMenuList = platformMenuMapper.getNotBuyMenuList();
                if (ObjectUtil.isNotEmpty(platformMenuList)) {
                    List<PlatformMenuPower> platformMenuPowerList = platformMenuPowerService.list(new LambdaQueryWrapper<PlatformMenuPower>().in(PlatformMenuPower::getMenuId, MenuUtils.getMenuIds(platformMenuList)));
                    MenuUtils.addPowerToMenu(platformMenuList, platformMenuPowerList);
                }
                return MenuUtils.convertMenu(platformMenuList);
            } else {
                // 租户普通用户
                List<PlatformMenu> platformMenuList = platformMenuMapper.getMenuListByUser(platformTenant.getTenantId(), platformUser.getUserId());
                if (ObjectUtil.isNotEmpty(platformMenuList)) {
                    List<PlatformMenuPower> platformMenuPowerList = platformMenuPowerService.list(new LambdaQueryWrapper<PlatformMenuPower>().in(PlatformMenuPower::getMenuId, MenuUtils.getMenuIds(platformMenuList)));
                    MenuUtils.addPowerToMenu(platformMenuList, platformMenuPowerList);
                }
                return MenuUtils.convertMenu(platformMenuList);
            }
        }
    }

    /**
     * 分页查询树形菜单列表
     *
     * @param platformMenuQueryVo 菜单视图对象
     * @return 分页树形菜单列表
     */
    @Override
    public PageData<Record> pageList(PlatformMenuQueryVo platformMenuQueryVo) {
        String tenantId = tokenUtils.getTenantId();
        PlatformTenant platformTenant = platformTenantService.getOne(new LambdaQueryWrapper<PlatformTenant>().eq(PlatformTenant::getTenantId, tenantId));
        // 如果是 平台级别租户
        if (platformTenant.getIsPlatform()) {
            // 正常查询即可
            Page<PlatformMenu> page = startPage();
            List<PlatformMenu> platformMenuList = platformMenuMapper.pageList(PlatformMenuBasic.INSTANCE.toPlatformMenu(platformMenuQueryVo), page);
            return PageData.build(new Page<>(page.getCurrent(), page.getSize(), page.getTotal()), getRecordList(platformMenuList));
        } else {
            // 租户
            List<PlatformMenu> platformMenuList = getNotBuyMenuList();
            return PageData.build(new Page<>(1, platformMenuList.size(), platformMenuList.size()), getRecordList(platformMenuList));
        }
    }

    private List<Record> getRecordList(List<PlatformMenu> platformMenuList) {
        if (ObjectUtil.isNotEmpty(platformMenuList)) {
            List<PlatformMenuPower> platformMenuPowerList = platformMenuPowerService.list(new LambdaQueryWrapper<PlatformMenuPower>().in(PlatformMenuPower::getMenuId, MenuUtils.getMenuIds(platformMenuList)));
            if (ObjectUtil.isNotEmpty(platformMenuPowerList)) {
                MenuUtils.addPowerToMenu(platformMenuList, platformMenuPowerList);
            }
        }
        return MenuUtils.convertMenu(platformMenuList);
    }

}
